package cn.dakaqi.activity.sign.record.services;

import cn.dakaqi.activity.services.ActivityDao;
import cn.dakaqi.activity.sign.services.ActivitySignService;
import cn.dakaqi.entities.ActivitySign;
import cn.dakaqi.entities.ActivitySignRecord;
import cn.dakaqi.member.service.VolunteerService;
import cn.dakaqi.utils.Clock;
import cn.dakaqi.utils.DKQConstant;
import cn.dakaqi.utils.DateUtil;
import cn.dakaqi.utils.exception.ServiceRuntimeException;
import cn.dakaqi.utils.latitude.LatitudeUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springside.modules.persistence.DynamicSpecifications;
import org.springside.modules.persistence.SearchFilter;

import java.awt.*;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by chunyang on 2016/4/17.
 */
@Component(value = "activitySignRecordService")
@Transactional
public class ActivitySignRecordServiceImpl implements ActivitySignRecordService
{
    @Autowired
    ActivityDao activityDao;
    @Autowired
    ActivitySignRecordDao activitySignRecordDao;
    @Autowired
    ActivitySignService activitySignService;
    @Autowired
    VolunteerService volunteerService;

    @Override
    public void save(String param) throws ServiceRuntimeException
    {
        JSONObject jsonObject = JSON.parseObject(param);
        String memberCode = jsonObject.getString("memberCode");
        String activityCode = jsonObject.getString("activityCode");
        double lng = jsonObject.getDouble("lng");
        double lat = jsonObject.getDouble("lat");
        ActivitySignRecord activitySignRecord = new ActivitySignRecord();
        activitySignRecord.setVolunteer(volunteerService.findByMemberCode(memberCode));
        activitySignRecord.setActivity(this.activityDao.findByActivityCode(activityCode));
        activitySignRecord.setCreateTime(Clock.DEFAULT.getCurrentDate());
        activitySignRecord.setLng(lng);
        activitySignRecord.setLat(lat);
        Map<String,String> address = LatitudeUtils.getGeocoderAddress(lat, lng);
        if(null != address)
            activitySignRecord.setAdress(address.get("address"));
        this.save(activitySignRecord);
    }

    @Override
    public void save(ActivitySignRecord activitySignRecord) throws ServiceRuntimeException
    {
        //检查活动是否已被封存
        if(activitySignRecord.getActivity().getLocked() == DKQConstant.ACTIVITY_LOCK)
            throw new ServiceRuntimeException("活动已被封存,不可以打卡");

        //检查活动的签到处是否在指定的范围内
        if(checkDdistance(activitySignRecord) == false)
        {
            throw new ServiceRuntimeException("未到活动现场,不可以打卡");
        }
        //检查当前用户是否有签到未签出的活动

        //保存签到记录
        this.activitySignRecordDao.save(activitySignRecord);
        //检查当前用户当前活动的所有打卡记录
        List<ActivitySignRecord> list = this.queryByMemberAndActivity(activitySignRecord.getVolunteer().getId(), activitySignRecord.getActivity().getId(), 1);
        if (null == list)
            return;
        //若有2次以上的签到记录，则记录公益时间
        if(list.size() >=2)
        {
            //检查当前用户是否已在本次活动的公益记录
            ActivitySign data = activitySignService.queryByMemberAndActivity(activitySignRecord.getVolunteer().getId(),activitySignRecord.getActivity().getId());
            if(null == data)
            {
                ActivitySign activitySign = new ActivitySign();
                activitySign.setLat(activitySignRecord.getLat());
                activitySign.setLng(activitySignRecord.getLng());
                activitySign.setVolunteer(activitySignRecord.getVolunteer());
                activitySign.setActivity(activitySignRecord.getActivity());
                activitySign.setTimes(0);
                activitySign.setCreateTime(activitySignRecord.getCreateTime());
                activitySign.setPlatform(activitySignRecord.getActivity().getPlatform());
                activitySignService.save(activitySign);
                return;
            }
            int times = 0,oldTime = data.getTimes();
            //计算两次签到时间的差
            String firstRecord = this.findFirstRecord(activitySignRecord.getVolunteer().getId(),activitySignRecord.getActivity().getId());
            String lastRecord = this.findLastRecord(activitySignRecord.getVolunteer().getId(), activitySignRecord.getActivity().getId());

            //本次活动实际时长
            int tagetTimes = 0;
            String startTime = activitySignRecord.getActivity().getStartTime();
            String endTime = activitySignRecord.getActivity().getEndTime();
            try
            {
                tagetTimes = DateUtil.countMinutes(startTime,endTime);
                times = DateUtil.countMinutes(firstRecord,lastRecord);
                if(times>=tagetTimes)
                    times = tagetTimes;

            } catch (Exception e)
            {
                e.printStackTrace();
            }
            if(times>0)
            {
                data.setTimes(times);
                activitySignService.updateTimes(data, oldTime);
            }
        }
        else
        {
            ActivitySign activitySign = new ActivitySign();
            activitySign.setLat(activitySignRecord.getLat());
            activitySign.setLng(activitySignRecord.getLng());
            activitySign.setVolunteer(activitySignRecord.getVolunteer());
            activitySign.setActivity(activitySignRecord.getActivity());
            activitySign.setTimes(0);
            activitySign.setCreateTime(activitySignRecord.getCreateTime());
            activitySign.setPlatform(activitySignRecord.getActivity().getPlatform());
            activitySignService.save(activitySign);
        }
    }

    /**
     * 检查是不是在有效的范围内打卡
     * @param activitySignRecord
     * @return
     */
    private boolean checkDdistance(ActivitySignRecord activitySignRecord)
    {
        if(activitySignRecord.getActivity().getScope()<0)
            return true;

        //计算两点间的距离
        double distance = LatitudeUtils.GetDistance(activitySignRecord.getLng(),activitySignRecord.getLat(),activitySignRecord.getActivity().getLng(),activitySignRecord.getActivity().getLat());
        if(distance>activitySignRecord.getActivity().getScope())
            return false;

        return true;
    }

    @Override
    public Page<ActivitySignRecord> queryByMember(String memberCode, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String,Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("volunteer.memberCode", new SearchFilter("volunteer.memberCode", SearchFilter.Operator.EQ, memberCode));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec, pageRequest);
    }

    @Override
    public Page<ActivitySignRecord> queryByMember(Long volunteerId, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String,Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("volunteer.id", new SearchFilter("volunteer.id", SearchFilter.Operator.EQ, volunteerId));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec, pageRequest);
    }

    @Override
    public Page<ActivitySignRecord> queryByActivity(String activityCode, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String,Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("activity.activityCode", new SearchFilter("activity.activityCode", SearchFilter.Operator.EQ, activityCode));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec, pageRequest);
    }

    @Override
    public Page<ActivitySignRecord> queryByActivity(Long activityId, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String,Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("activity.id", new SearchFilter("activity.id", SearchFilter.Operator.EQ, activityId));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec, pageRequest);
    }

    @Override
    public List<ActivitySignRecord> queryByMemberAndActivity(String memberCode, String activityCode, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String,Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("volunteer.memberCode", new SearchFilter("volunteer.memberCode", SearchFilter.Operator.EQ, memberCode));
        filters.put("activity.activityCode", new SearchFilter("activity.activityCode", SearchFilter.Operator.EQ, activityCode));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec);
    }

    @Override
    public List<ActivitySignRecord> queryByMemberAndActivity(Long volunteerId, Long activityId, int pageNumber) throws ServiceRuntimeException
    {
        Sort sort = new Sort(Sort.Direction.DESC, "createTime");
        PageRequest pageRequest = new PageRequest(pageNumber - 1, 20, sort);

        Map<String,Object> map = new HashMap<String, Object>();
        //map.put("LIKE_NAME",name);
        //Map<String, SearchFilter> filters = SearchFilter.parse(map);

        Map<String, SearchFilter> filters = Maps.newHashMap();
        filters.put("volunteer.id", new SearchFilter("volunteer.id", SearchFilter.Operator.EQ, volunteerId));
        filters.put("activity.id", new SearchFilter("activity.id", SearchFilter.Operator.EQ, activityId));
        Specification<ActivitySignRecord> spec = DynamicSpecifications.bySearchFilter(filters.values(), ActivitySignRecord.class);
        return this.activitySignRecordDao.findAll(spec);
    }

    @Override
    public String findFirstRecord(Long volunteerId, Long activityId) throws ServiceRuntimeException
    {
        return this.activitySignRecordDao.findFirstRecord(volunteerId,activityId);
    }

    @Override
    public String findLastRecord(Long volunteerId, Long activityId) throws ServiceRuntimeException
    {
        return this.activitySignRecordDao.findLastRecord(volunteerId,activityId);
    }
}
